package com.njcb.ams.support.exception;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Map;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 对于难以应付的意外 如 I/O异常 编程缺陷，硬件故障，配置错误，文件丢失，服务器无法使用 需抛出此未检查异常
 * 
 * @author liuyanlong
 *
 */
public class AppException extends RuntimeException implements SystemException {

	private static final long serialVersionUID = 1L;
	
	private static final Logger logger = LoggerFactory.getLogger(AppException.class);

	public static AppException wrap(Throwable exception, String errorCode) {
		if (exception instanceof AppException) {
			AppException se = (AppException) exception;
			return se;
		} else {
			return new AppException(exception.getMessage(), errorCode, exception);
		}
	}

	public static AppException wrap(Throwable exception) {
		return wrap(exception, null);
	}

	private String errorCode;
	private final Map<String, Object> properties = new TreeMap<String, Object>();

	protected AppException(Throwable exception) {
		super(exception);
	}

	protected AppException(String errorCode) {
		this.errorCode = errorCode;
	}

	protected AppException(String message, String errorCode) {
		super(message);
		this.errorCode = errorCode;
		if(null == errorCode || errorCode.length() != 10){
			logger.warn("错误码应包含[系统简称（3位）＋模块（2位）＋信息类型（1位）＋序号（4位）]");
		}
	}

	protected AppException(String message, String errorCode, Throwable cause) {
		super(message, cause);
		this.errorCode = String.valueOf(errorCode);
	}

	@Override
	public String getErrorCode() {
		return errorCode;
	}

	public AppException setErrorCode(String errorCode) {
		this.errorCode = errorCode;
		return this;
	}

	public Map<String, Object> getProperties() {
		return properties;
	}

	@SuppressWarnings("unchecked")
	public <T> T get(String name) {
		return (T) properties.get(name);
	}

	public AppException set(String name, Object value) {
		properties.put(name, value);
		return this;
	}

	@Override
	public void printStackTrace(PrintStream s) {
		synchronized (s) {
			printStackTrace(new PrintWriter(s));
		}
	}

	@Override
	public void printStackTrace(PrintWriter s) {
		synchronized (s) {
			s.println(this);
			s.println("\t-------------------------------");
			if (errorCode != null) {
				s.println("\terrorCode:" + errorCode + "\t" + ExceptionUtil.getUserErrorText(errorCode));
			}
			for (String key : properties.keySet()) {
				s.println("\t" + key + "=[" + properties.get(key) + "]");
			}
			s.println("\t-------------------------------");
			StackTraceElement[] trace = getStackTrace();
			for (int i = 0; i < trace.length; i++) {
				s.println("\tat " + trace[i]);
			}

			Throwable ourCause = getCause();
			if (ourCause != null) {
				ourCause.printStackTrace(s);
			}
			s.flush();
		}
	}

}
